/******************************************************************************************
Copyright(C), 2019-2020, Linyar.
文件名：L_MPP40_venc.c
作者：燕卫博	版本：V1.0	创建日期：2021.5.27
文件描述：
    对Hi3516DV300视频编码过程调用MPP操作的封装。
版本信息：
    9Hv2，个人。
历史修改记录：
1. 2021-8-15:V1.1 燕卫博
从STv9-t拷贝更改，仅考虑适配9Hv2工程。

******************************************************************************************/
//                                              ↓
//+------------------------------------------------------------------------------------------+
//|                                          文件说明
//+------------------------------------------------------------------------------------------+
//|      和VPSS不同，VENC只有通道的概念。VENC模块由编码通道子模块（VENC）和编码协议子模块
//| （H.264/H.265/JPEG/MJPEG/PRORES）组成。每个VENC通道又包括码率控制器和编码器。
//|      在设置VENC通道时分为以下几个部分：
//|      1.对VENC通道属性的设置
//|      2.对RC码率控制器属性的设置
//|      其中对GOP的设置属于一。
//|  在调用VENC通道时编码图像不能超过编码通道尺寸。
//|      Hi3516CV500/Hi3516DV300/Hi3559V200/Hi3556V200/Hi3516AV300/Hi3516EV200/Hi3516EV300/
//|  Hi3518EV300/Hi3516DV200支持的最大VENC通道数为16。——《参考》P1008
//+------------------------------------------------------------------------------------------+
//                                              ↓
//+------------------------------------------------------------------------------------------+
//|                                         头文件包含
//+------------------------------------------------------------------------------------------+
/*|*/  #include "L_MPP40_venc.h"
/*|*/  #include "L_MPP40_debug.h"
//+------------------------------------------------------------------------------------------+
//                                              ↓
//+------------------------------------------------------------------------------------------+
//|                                         参数宏定义
//+------------------------------------------------------------------------------------------+
/*|*/  #define SOURCEFRAMERATE 30
//|
//|    #define SAVE_STREAM_TO_FILE
//|
/*|*/  #ifdef SAVE_STREAM_TO_FILE
/*|*/  #define VENC_CHN0_FILENAME  "l_video_chn0"
/*|*/  #define VENC_CHN1_FILENAME  "l_video_chn1"
/*|*/  #define VENC_CHN2_FILENAME  "l_video_chn2"
/*|*/  #define VENC_CHN3_FILENAME  "l_video_chn3"
/*|*/  #define VENC_CHN4_FILENAME  "l_video_chn4"
/*|*/  #define VENC_CHN5_FILENAME  "l_video_chn5"
/*|*/  #define VENC_CHN6_FILENAME  "l_video_chn6"
/*|*/  #define VENC_CHN7_FILENAME  "l_video_chn7"
/*|*/  #define VENC_CHN8_FILENAME  "l_video_chn8"
/*|*/  #define VENC_CHN9_FILENAME  "l_video_chn9"
/*|*/  #define VENC_CHN10_FILENAME "l_video_chn10"
/*|*/  #define VENC_CHN11_FILENAME "l_video_chn11"
/*|*/  #define VENC_CHN12_FILENAME "l_video_chn12"
/*|*/  #define VENC_CHN13_FILENAME "l_video_chn13"
/*|*/  #define VENC_CHN14_FILENAME "l_video_chn14"
/*|*/  #define VENC_CHN15_FILENAME "l_video_chn15"
/*|*/  #endif
//+------------------------------------------------------------------------------------------+
//                                              ↓
//+------------------------------------------------------------------------------------------+
//|                                          全局变量
//+------------------------------------------------------------------------------------------+
//|    用于记录通道被占用的状态
//|    0：未使用 1：用于视频流编码
/*|*/  static int EnabledVencChn[VENC_MAX_CHN_NUM]={0};
//|
/*|*/  VENC_PARA_S stVENCpara_default=
/*|*/  {
/*|*/      .VencChn=0,
/*|*/      .enPayLoad=PT_H264,
/*|*/      .enSize=PIC_1080P,
/*|*/      .enGopMode=VENC_GOPMODE_NORMALP,
/*|*/      .u32Gop=30,
/*|*/      .enRcMode=RC_CBR,
/*|*/      .u32FrameRate=30,
/*|*/      .u32Profile=0,
/*|*/      .s32FrameNumber=-1,
/*|*/  };
//+------------------------------------------------------------------------------------------+

//+------------------------------------------------------------------------------------------+
//|  函数名称：L_VENC_CreateChnForVideo
//|  功能描述：在MPP4.0上根据指定的参数建立视频编码的VENC通道。只支持H264和H265编码。
//|  参数说明：VENC_PARA_S类型的结构体指针
//|  返回值说明：成功返回0
//|  备注：本函数建立并初始化通道之后，MPP视频编码初始化全部流程结束，但未绑定到前级模块，需
//|        要手动传入待编码图像。
//|  函数使用：传入NULL则调用默认配置进行编码。建立VENC_PARA_S类型的结构体进行初始化后，传入
//|            结构体指针即可初始化相应通道的编码。
//|  一个客观存在的注意项：同时能够启动的VENC通道数取决于当前内存多少以及MMZ分配方式等。
//+------------------------------------------------------------------------------------------+
int L_VENC_CreateChnForVideo(VENC_PARA_S *pstVENCpara)
{
    HI_S32 s32Ret=HI_SUCCESS;

    if(pstVENCpara==NULL)
    {
        pstVENCpara=&stVENCpara_default;
    }

    if(EnabledVencChn[pstVENCpara->VencChn])
    {
        LOGD("[MPP-VENC-DEBUG]L_VENC_CreateChnAndStart:The Channel choosed for ENCODE has already been inited!\n");
        return -1;
    }

    //----------------------------------------
    //——————————————关于GOP结构——————————————
    //Hi3516DV300支持的GOP结构有NORMALP、
    //DUALP、SMARTP。——《参考》P850
    //----------------------------------------
    VENC_GOP_ATTR_S stGopAttr;
    switch(pstVENCpara->enGopMode)
    {
        case VENC_GOPMODE_NORMALP:
            stGopAttr.enGopMode=VENC_GOPMODE_NORMALP;
            stGopAttr.stNormalP.s32IPQpDelta=2;
        break;
        case VENC_GOPMODE_SMARTP:
            stGopAttr.enGopMode=VENC_GOPMODE_SMARTP;
            stGopAttr.stSmartP.s32BgQpDelta=4;
            stGopAttr.stSmartP.s32ViQpDelta=2;
            stGopAttr.stSmartP.u32BgInterval=90;
        break;

        case VENC_GOPMODE_DUALP:
            stGopAttr.enGopMode=VENC_GOPMODE_DUALP;
            stGopAttr.stDualP.s32IPQpDelta=4;
            stGopAttr.stDualP.s32SPQpDelta=2;
            stGopAttr.stDualP.u32SPInterval=3;
        break;

        default:
            LOGE("[MPP-VENC-ERROR]L_VENC_CreateChnAndStart:Unsupported GOPMODE for Hi3519AV100! Changed to NORMALP!\n");
            stGopAttr.enGopMode=VENC_GOPMODE_NORMALP;
            stGopAttr.stNormalP.s32IPQpDelta=2;
        break;
    }

    //----------------------------------------
    //源帧率和sensor适配
    //和老版本例程相比，在所参考版本的例程中，
    //bRcnRefShareBuf被设置为HI_FALSE
    //----------------------------------------
    HI_U32 u32SrcFrameRate=SOURCEFRAMERATE;
    HI_U32 u32FrameRate=pstVENCpara->u32FrameRate;
    HI_U32 u32StatTime=1;
    HI_BOOL bRcnRefShareBuf=HI_FALSE;

    //----------------------------------------
    //GOP分组即I帧和I帧之间的间隔，表现在码流上
    //为多包模式下，SPS、PPS、SEI包的间隔数。
    //单包或多包模式见《参考》P859。
    //----------------------------------------
    HI_U32 u32Gop=pstVENCpara->u32Gop;

    //----------------------------------------
    //编码尺寸的支持需要在此处和PIC_SIZE_E中自行添加。
    //如果考虑到资源，在RC控制选择处也要添加
    //对应处理，以防止按照最大比特率编码。
    //----------------------------------------
    SIZE_S stPicSize;
    switch(pstVENCpara->enSize)
    {
        case PIC_VGA:
            stPicSize.u32Width=640;
            stPicSize.u32Height=480;
        break;
        case PIC_720P:
            stPicSize.u32Width=1280;
            stPicSize.u32Height=720;
        break;
        case PIC_1080P:
            stPicSize.u32Width=1920;
            stPicSize.u32Height=1080;
        break;
        case PIC_2592x1944:
            stPicSize.u32Width=2592;
            stPicSize.u32Height=1944;
        break;
        case PIC_3840x2160:
            stPicSize.u32Width=3840;
            stPicSize.u32Height=2160;
        break;
        default:
            stPicSize.u32Width=3840;
            stPicSize.u32Height=2160;
        break;
    }
    VENC_CHN_ATTR_S stVencChnAttr;
    memcpy(&stVencChnAttr.stGopAttr,&stGopAttr,sizeof(VENC_GOP_ATTR_S));
    stVencChnAttr.stVencAttr.enType=pstVENCpara->enPayLoad;
    //----------------------------------------
    //本程序中分辨率的修改为静态配置，故最大
    //宽高和目的宽高设置相同。
    //----------------------------------------
    stVencChnAttr.stVencAttr.u32MaxPicWidth=stPicSize.u32Width;
    stVencChnAttr.stVencAttr.u32MaxPicHeight=stPicSize.u32Height;
    stVencChnAttr.stVencAttr.u32PicWidth   =stPicSize.u32Width;
    stVencChnAttr.stVencAttr.u32PicHeight  =stPicSize.u32Height;
    stVencChnAttr.stVencAttr.u32Profile    =pstVENCpara->u32Profile;
    stVencChnAttr.stVencAttr.u32BufSize    =stPicSize.u32Width*stPicSize.u32Height*2;
    stVencChnAttr.stVencAttr.bByFrame      =HI_TRUE;//码流按帧获取还是按包获取

    //----------------------------------------
    //关于SMARTP下对u32StatTime的设置，直接复制例程
    //----------------------------------------
    if(VENC_GOPMODE_SMARTP==pstVENCpara->enGopMode)
    {
        u32StatTime=stGopAttr.stSmartP.u32BgInterval/u32Gop;
    }
    else
    {
        u32StatTime=1;
    }

    switch(pstVENCpara->enPayLoad)
    {
        case PT_H265:
        {
            if(RC_CBR==pstVENCpara->enRcMode)
            {
                VENC_H265_CBR_S    stH265Cbr;

                stVencChnAttr.stRcAttr.enRcMode=VENC_RC_MODE_H265CBR;
                stH265Cbr.u32Gop          =u32Gop;
                stH265Cbr.u32StatTime     =u32StatTime; /* stream rate statics time(s) */
                stH265Cbr.u32SrcFrameRate =u32SrcFrameRate; /* input(vi) frame rate */
                stH265Cbr.fr32DstFrameRate=u32FrameRate; /* target frame rate */
                switch(pstVENCpara->enSize)
                {
                    case PIC_VGA:
                        stH265Cbr.u32BitRate = 1024 + 512*u32SrcFrameRate/30;
                        break;
                    case PIC_720P:
                        stH265Cbr.u32BitRate = 1024*2 + 1024*u32SrcFrameRate/30;
                        break;
                    case PIC_1080P:
                        stH265Cbr.u32BitRate = 1024*2 + 2048*u32SrcFrameRate/30;
                        break;
                    case PIC_2592x1944:
                        stH265Cbr.u32BitRate = 1024 * 3 + 3072*u32FrameRate/30;
                        break;
                    case PIC_3840x2160:
                        stH265Cbr.u32BitRate = 1024 * 5  + 5120*u32FrameRate/30;
                        break;
                    default :
                        stH265Cbr.u32BitRate = 1024 * 15 + 2048*u32FrameRate/30;
                        break;
                }
                memcpy(&stVencChnAttr.stRcAttr.stH265Cbr,&stH265Cbr,sizeof(VENC_H265_CBR_S));
            }
            else if(RC_FIXQP==pstVENCpara->enRcMode)
            {
                VENC_H265_FIXQP_S    stH265FixQp;

                stVencChnAttr.stRcAttr.enRcMode=VENC_RC_MODE_H265FIXQP;
                stH265FixQp.u32Gop            =30;
                stH265FixQp.u32SrcFrameRate   =u32SrcFrameRate;
                stH265FixQp.fr32DstFrameRate  =u32FrameRate;
                stH265FixQp.u32IQp            =25;
                stH265FixQp.u32PQp            =30;
                stH265FixQp.u32BQp            =32;
                memcpy(&stVencChnAttr.stRcAttr.stH265FixQp,&stH265FixQp,sizeof(VENC_H265_FIXQP_S));
            }
            else if(RC_VBR==pstVENCpara->enRcMode)
            {
                VENC_H265_VBR_S stH265Vbr;

                stVencChnAttr.stRcAttr.enRcMode=VENC_RC_MODE_H265VBR;
                stH265Vbr.u32Gop         =u32Gop;
                stH265Vbr.u32StatTime    =u32StatTime;
                stH265Vbr.u32SrcFrameRate=u32SrcFrameRate;
                stH265Vbr.fr32DstFrameRate=u32FrameRate;
                switch(pstVENCpara->enSize)
                {
                    case PIC_VGA:
                        stH265Vbr.u32MaxBitRate=1024 + 512*u32SrcFrameRate/30;
                        break;
                    case PIC_720P:
                        stH265Vbr.u32MaxBitRate=1024*2 + 1024*u32SrcFrameRate/30;
                        break;
                    case PIC_1080P:
                        stH265Vbr.u32MaxBitRate=1024*2 + 2048*u32SrcFrameRate/30;
                        break;
                    case PIC_2592x1944:
                        stH265Vbr.u32MaxBitRate = 1024 * 3 + 3072*u32FrameRate/30;
                        break;
                    case PIC_3840x2160:
                        stH265Vbr.u32MaxBitRate = 1024 * 5  + 5120*u32FrameRate/30;
                        break;
                    default :
                        stH265Vbr.u32MaxBitRate = 1024 * 15 + 2048*u32FrameRate/30;
                        break;
                }
                memcpy(&stVencChnAttr.stRcAttr.stH265Vbr,&stH265Vbr,sizeof(VENC_H265_VBR_S));
            }
            else if(RC_AVBR==pstVENCpara->enRcMode)
            {
                VENC_H265_AVBR_S stH265AVbr;

                stVencChnAttr.stRcAttr.enRcMode=VENC_RC_MODE_H265AVBR;
                stH265AVbr.u32Gop       =u32Gop;
                stH265AVbr.u32StatTime  =u32StatTime;
                stH265AVbr.u32SrcFrameRate=u32SrcFrameRate;
                stH265AVbr.fr32DstFrameRate=u32FrameRate;
                switch(pstVENCpara->enSize)
                {
                    case PIC_VGA:
                        stH265AVbr.u32MaxBitRate=1024 + 512*u32SrcFrameRate/30;
                        break;
                    case PIC_720P:
                        stH265AVbr.u32MaxBitRate=1024*2 + 1024*u32SrcFrameRate/30;
                        break;
                    case PIC_1080P:
                        stH265AVbr.u32MaxBitRate=1024*2 + 2048*u32SrcFrameRate/30;
                        break;
                    case PIC_2592x1944:
                        stH265AVbr.u32MaxBitRate = 1024 * 3 + 3072*u32FrameRate/30;
                        break;
                    case PIC_3840x2160:
                        stH265AVbr.u32MaxBitRate = 1024 * 5  + 5120*u32FrameRate/30;
                        break;
                    default :
                        stH265AVbr.u32MaxBitRate = 1024 * 15 + 2048*u32FrameRate/30;
                        break;
                }
                memcpy(&stVencChnAttr.stRcAttr.stH265AVbr,&stH265AVbr,sizeof(VENC_H265_AVBR_S));
            }
            else if(RC_QPMAP==pstVENCpara->enRcMode)
            {
                VENC_H265_QPMAP_S stH265QpMap;

                stVencChnAttr.stRcAttr.enRcMode=VENC_RC_MODE_H265QPMAP;
                stH265QpMap.u32Gop         =u32Gop;
                stH265QpMap.u32StatTime    =u32StatTime;
                stH265QpMap.u32SrcFrameRate=u32SrcFrameRate;
                stH265QpMap.fr32DstFrameRate=u32FrameRate;
                stH265QpMap.enQpMapMode     =VENC_RC_QPMAP_MODE_MEANQP;
                memcpy(&stVencChnAttr.stRcAttr.stH265QpMap,&stH265QpMap,sizeof(VENC_H265_QPMAP_S));
            }
            else
            {
                LOGE("[MPP-VENC-ERROR]L_VENC_CreateChnAndStart:RC mode(%d) not support!\n",pstVENCpara->enRcMode);
                return HI_FAILURE;
            }
            stVencChnAttr.stVencAttr.stAttrH265e.bRcnRefShareBuf=bRcnRefShareBuf;
        }
        break;
        case PT_H264:
        {
            if(RC_CBR==pstVENCpara->enRcMode)
            {
                VENC_H264_CBR_S stH264Cbr;

                stVencChnAttr.stRcAttr.enRcMode=VENC_RC_MODE_H264CBR;
                stH264Cbr.u32Gop              =u32Gop; /*the interval of IFrame*/
                stH264Cbr.u32StatTime         =u32StatTime; /* stream rate statics time(s) */
                stH264Cbr.u32SrcFrameRate     =u32SrcFrameRate; /* input(vi) frame rate */
                stH264Cbr.fr32DstFrameRate    =u32FrameRate; /* target frame rate */
                switch(pstVENCpara->enSize)
                {
                    case PIC_VGA:
                        stH264Cbr.u32BitRate=1024 + 512*u32SrcFrameRate/30;
                        break;
                    case PIC_720P:
                        stH264Cbr.u32BitRate=1024*2  + 1024*u32SrcFrameRate/30;
                        break;
                    case PIC_1080P:
                        stH264Cbr.u32BitRate=1024*2  + 2048*u32SrcFrameRate/30;
                        break;
                    case PIC_2592x1944:
                        stH264Cbr.u32BitRate = 1024 * 3  + 3072*u32FrameRate/30;
                        break;
                    case PIC_3840x2160:
                        stH264Cbr.u32BitRate = 1024 * 5 + 5120*u32FrameRate/30;
                        break;
                    default :
                        stH264Cbr.u32BitRate = 1024 * 15 + 2048*u32FrameRate/30;
                        break;
                }

                memcpy(&stVencChnAttr.stRcAttr.stH264Cbr,&stH264Cbr,sizeof(VENC_H264_CBR_S));
            }
            else if(RC_FIXQP==pstVENCpara->enRcMode)
            {
                VENC_H264_FIXQP_S stH264FixQp;

                stVencChnAttr.stRcAttr.enRcMode=VENC_RC_MODE_H264FIXQP;
                stH264FixQp.u32Gop         =30;
                stH264FixQp.u32SrcFrameRate=u32SrcFrameRate;
                stH264FixQp.fr32DstFrameRate=u32FrameRate;
                stH264FixQp.u32IQp         =25;
                stH264FixQp.u32PQp         =30;
                stH264FixQp.u32BQp         =32;
                memcpy(&stVencChnAttr.stRcAttr.stH264FixQp,&stH264FixQp,sizeof(VENC_H264_FIXQP_S));
            }
            else if(RC_VBR==pstVENCpara->enRcMode)
            {
                VENC_H264_VBR_S    stH264Vbr;

                stVencChnAttr.stRcAttr.enRcMode=VENC_RC_MODE_H264VBR;
                stH264Vbr.u32Gop         =u32Gop;
                stH264Vbr.u32StatTime    =u32StatTime;
                stH264Vbr.u32SrcFrameRate=u32SrcFrameRate;
                stH264Vbr.fr32DstFrameRate=u32FrameRate;
                switch(pstVENCpara->enSize)
                {
                    case PIC_VGA:
                        stH264Vbr.u32MaxBitRate=1024 + 512*u32SrcFrameRate/30;
                        break;
                    case PIC_720P:
                        stH264Vbr.u32MaxBitRate=1024*2   + 1024*u32SrcFrameRate/30;
                        break;
                    case PIC_1080P:
                        stH264Vbr.u32MaxBitRate=1024*2   + 2048*u32SrcFrameRate/30;
                        break;
                    case PIC_2592x1944:
                        stH264Vbr.u32MaxBitRate = 1024 * 3   + 3072*u32FrameRate/30;
                        break;
                    case PIC_3840x2160:
                        stH264Vbr.u32MaxBitRate = 1024 * 5   + 5120*u32FrameRate/30;
                        break;
                    default :
                        stH264Vbr.u32MaxBitRate = 1024 * 15  + 2048*u32FrameRate/30;
                        break;
                }
                memcpy(&stVencChnAttr.stRcAttr.stH264Vbr,&stH264Vbr,sizeof(VENC_H264_VBR_S));
            }
            else if(RC_AVBR==pstVENCpara->enRcMode)
            {
                VENC_H264_VBR_S stH264AVbr;

                stVencChnAttr.stRcAttr.enRcMode=VENC_RC_MODE_H264AVBR;
                stH264AVbr.u32Gop         =u32Gop;
                stH264AVbr.u32StatTime    =u32StatTime;
                stH264AVbr.u32SrcFrameRate=u32SrcFrameRate;
                stH264AVbr.fr32DstFrameRate=u32FrameRate;
                switch(pstVENCpara->enSize)
                {
                    case PIC_VGA:
                        stH264AVbr.u32MaxBitRate=1024 + 512*u32SrcFrameRate/30;
                        break;
                    case PIC_720P:
                        stH264AVbr.u32MaxBitRate=1024*2   + 1024*u32SrcFrameRate/30;
                        break;
                    case PIC_1080P:
                        stH264AVbr.u32MaxBitRate=1024*2   + 2048*u32SrcFrameRate/30;
                        break;
                    case PIC_2592x1944:
                        stH264AVbr.u32MaxBitRate = 1024 * 3   + 3072*u32FrameRate/30;
                        break;
                    case PIC_3840x2160:
                        stH264AVbr.u32MaxBitRate = 1024 * 5   + 5120*u32FrameRate/30;
                        break;
                    default :
                        stH264AVbr.u32MaxBitRate = 1024 * 15  + 2048*u32FrameRate/30;
                        break;
                }
                memcpy(&stVencChnAttr.stRcAttr.stH264AVbr,&stH264AVbr,sizeof(VENC_H264_AVBR_S));
            }
            else if(RC_QPMAP==pstVENCpara->enRcMode)
            {
                VENC_H264_QPMAP_S stH264QpMap;

                stVencChnAttr.stRcAttr.enRcMode=VENC_RC_MODE_H264QPMAP;
                stH264QpMap.u32Gop         =u32Gop;
                stH264QpMap.u32StatTime    =u32StatTime;
                stH264QpMap.u32SrcFrameRate=u32SrcFrameRate;
                stH264QpMap.fr32DstFrameRate=u32FrameRate;
                memcpy(&stVencChnAttr.stRcAttr.stH264QpMap,&stH264QpMap,sizeof(VENC_H264_QPMAP_S));
            }
            else
            {
                LOGE("[MPP-VENC-ERROR]L_VENC_CreateChnAndStart:RC mode(%d) not support!\n",pstVENCpara->enRcMode);
                return HI_FAILURE;
            }
            stVencChnAttr.stVencAttr.stAttrH264e.bRcnRefShareBuf=bRcnRefShareBuf;
        }
        break;
        default:
            LOGE("[MPP-VENC-ERROR]L_VENC_CreateChnAndStart:Unsupport payload in this function!\n");
            return HI_ERR_VENC_NOT_SUPPORT;
    }

    s32Ret=HI_MPI_VENC_CreateChn(pstVENCpara->VencChn,&stVencChnAttr);
    if(HI_SUCCESS!=s32Ret)
    {
        LOGE("[MPP-VENC-ERROR]L_VENC_CreateChnAndStart:HI_MPI_VENC_CreateChn[%d] faild with %#x!\n",pstVENCpara->VencChn,s32Ret);
        HI_MPI_VENC_DestroyChn(pstVENCpara->VencChn);
        return s32Ret;
    }

    //----------------------------------------
    //VENC开启编码通道接收输入图像
    //----------------------------------------
    VENC_RECV_PIC_PARAM_S stRecvParam;
    stRecvParam.s32RecvPicNum=pstVENCpara->s32FrameNumber;//编码数量
    s32Ret=HI_MPI_VENC_StartRecvFrame(pstVENCpara->VencChn,&stRecvParam);
    if(HI_SUCCESS!=s32Ret)
    {
        LOGE("[MPP-VENC-ERROR]L_VENC_CreateChnAndStart:HI_MPI_VENC_StartRecvPic faild with %#x!\n",s32Ret);
        L_VENC_DeInit(pstVENCpara->VencChn);
        return s32Ret;
    }

    //----------------------------------------
    //将已经初始化的VENC通道记录下来
    //----------------------------------------
    EnabledVencChn[pstVENCpara->VencChn]=1;

    return 0;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：L_VENC_DeInit
//|  功能描述：进行VENC通道去初始化。
//|  参数说明：VENC通道号
//|  返回值说明：成功返回0
//|  备注：设置指定通道停止编码并销毁。
//+------------------------------------------------------------------------------------------+
void L_VENC_DeInit(VENC_CHN VencChn)
{
    HI_MPI_VENC_StopRecvFrame(VencChn);
    HI_MPI_VENC_DestroyChn(VencChn);
    //----------------------------------------
    //将已经去初始化的VENC通道记录下来
    //----------------------------------------
    EnabledVencChn[VencChn]=0;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：L_VENC_GetStream
//|  功能描述：从VENC通道中读取码流并处理。
//|  参数说明：循环结束标志，为false时结束循环；码流处理函数的函数名
//|  返回值说明：无
//|  备注：只能处理初始化为H264或H265编码的通道。
//+------------------------------------------------------------------------------------------+
void L_VENC_GetStream(bool *get_stream_enable,void (*pStreamFuction)(int i,VENC_STREAM_S *pstStream))
{
    HI_S32 i,s32Ret;
    fd_set Venc_readfds;
    HI_S32 VencFd[VENC_MAX_CHN_NUM];
    for(i=0;i<VENC_MAX_CHN_NUM;i++)
    {
        VencFd[i]=-1;
    }
    VENC_STREAM_S stStream;
    VENC_CHN_STATUS_S stStat;
    struct timeval TimeoutVal;
#ifdef SAVE_STREAM_TO_FILE
    HI_CHAR FileName[VENC_MAX_CHN_NUM][64];
    {
        //----------------------------------------
        //给每个通道保存下来的视频裸流文件起个名字
        //为了方便后续的更改和特定需求，
        //此版本不使用循环为通道赋值固定的文件前缀。
        //此处文件名长度不要超过 60Bytes ，
        //后续将根据通道荷载添加后缀名。
        //
        //此处的文件名只有使用到对应通道进行视频编码
        //时才有效。
        //----------------------------------------
        strcpy(&FileName[0][0],VENC_CHN0_FILENAME);
        strcpy(&FileName[1][0],VENC_CHN1_FILENAME);
        strcpy(&FileName[2][0],VENC_CHN2_FILENAME);
        strcpy(&FileName[3][0],VENC_CHN3_FILENAME);
        strcpy(&FileName[4][0],VENC_CHN4_FILENAME);
        strcpy(&FileName[5][0],VENC_CHN5_FILENAME);
        strcpy(&FileName[6][0],VENC_CHN6_FILENAME);
        strcpy(&FileName[7][0],VENC_CHN7_FILENAME);
        strcpy(&FileName[8][0],VENC_CHN8_FILENAME);
        strcpy(&FileName[9][0],VENC_CHN9_FILENAME);
        strcpy(&FileName[10][0],VENC_CHN10_FILENAME);
        strcpy(&FileName[11][0],VENC_CHN11_FILENAME);
        strcpy(&FileName[12][0],VENC_CHN12_FILENAME);
        strcpy(&FileName[13][0],VENC_CHN13_FILENAME);
        strcpy(&FileName[14][0],VENC_CHN14_FILENAME);
        strcpy(&FileName[15][0],VENC_CHN15_FILENAME);
    }
    FILE* pFile[VENC_MAX_CHN_NUM]={0};//每个通道保存时的文件描述符
    //----------------------------------------
    //查询每个已开启的通道的荷载类型，在对应文件名
    //字符串后添加后缀。
    //----------------------------------------
    PAYLOAD_TYPE_E enPayLoadType[VENC_MAX_CHN_NUM];//获取的每个通道荷载类型
    VENC_CHN_ATTR_S stVencChnAttr;//获取通道荷载类型时的属性接收变量
#endif
    HI_S32 maxfd=0;
    for(i=0;i<VENC_MAX_CHN_NUM;i++)
    {
        if(EnabledVencChn[i])//查看通道是否在开启状态
        {
#ifdef SAVE_STREAM_TO_FILE
            s32Ret=HI_MPI_VENC_GetChnAttr(i,&stVencChnAttr);
            if(s32Ret!=HI_SUCCESS)
            {
                LOGE("[MPP-VENC-ERROR]L_VENC_GetStream:HI_MPI_VENC_GetChnAttr Chn[%d] failed with %#x!\n",i,s32Ret);
                return;
            }
            enPayLoadType[i]=stVencChnAttr.stVencAttr.enType;
            //----------------------------------------
            //对图像流的保存在接收时打开并写入文件，
            //此处增加对检测到JPEG荷载时的略过处理.
            //对其它荷载打开对应的文件（仅支持H264、H265）。
            //----------------------------------------
            if(EnabledVencChn[i]==1)
            {
                switch(enPayLoadType[i])
                {
                    case PT_H264:
                        strcat(&FileName[i][0],".h264");
                    break;
                    case PT_H265:
                        strcat(&FileName[i][0],".h265");
                    break;
                    default:
                        LOGE("[MPP-VENC-ERROR]L_VENC_GetStream:Unsupported PayLoadType %d!",i);
                        return;
                    break;
                }

                pFile[i]=fopen(&FileName[i][0],"wb");
                if(!pFile[i])
                {
                    LOGE("[MPP-VENC-ERROR]L_VENC_GetStream:Open file[%s] failed!\n",&FileName[i][0]);
                    return;
                }
            }
#endif
            //----------------------------------------
            //将通道的VENC设备文件句柄存放起来，以便后续查询。
            //此处存放的句柄包括荷载为图像流的通道。
            //----------------------------------------
            VencFd[i]=HI_MPI_VENC_GetFd(i);
            if(VencFd[i]<0)
            {
                LOGE("[MPP-VENC-ERROR]L_VENC_GetStream:HI_MPI_VENC_GetFd failed with %#x!\n",VencFd[i]);
                return;
            }

            //----------------------------------------
            //获取句柄中最大者，便于后续使用select函数
            //----------------------------------------
            if(maxfd<=VencFd[i])
            {
                maxfd=VencFd[i];
            }
        }
    }
    while(*get_stream_enable)
    {
        FD_ZERO(&Venc_readfds);
        //----------------------------------------
        //select函数成功返回时会将未准备好的描述符位
        //清零，所以每次轮询都需要重新设置Venc_readfds。
        //----------------------------------------
        for(i=0;i<VENC_MAX_CHN_NUM;i++)
        {
            if(VencFd[i]>=0)
            {
                FD_SET(VencFd[i],&Venc_readfds);//将Venc句柄加入到Venc_readfds
            }
        }
        TimeoutVal.tv_sec=2;
        TimeoutVal.tv_usec=0;
        //----------------------------------------
        //select函数返回值小于0说明发生错误，
        //等于0说明在设置的时间范围内，监视的描述符
        //没有发生动作。大于0说明监视的描述符有可读
        //或可写的状态改变（取决于设置）。
        //----------------------------------------
        s32Ret=select(maxfd+1,&Venc_readfds,NULL,NULL,&TimeoutVal);//检查可读性。
        if(s32Ret<0)
        {
            LOGE("[MPP-VENC-ERROR]L_VENC_GetStream:Select error!\n");
            break;
        }
        else if(s32Ret==0)
        {
            LOGE("[MPP-VENC-ERROR]L_VENC_GetStream:Get VENC stream timeout.\n");
            continue;
        }
        else
        {
            for(i=0;i<VENC_MAX_CHN_NUM;i++)//在所有通道范围内轮询-->
            {
                if(EnabledVencChn[i])//其中已开启编码的通道-->
                {
                    if(FD_ISSET(VencFd[i],&Venc_readfds))//发生了读状态改变，则：
                    {
                        memset(&stStream,0,sizeof(stStream));
                        //----------------------------------------
                        //查询对应通道的状态，获取码流包数量等信息
                        //----------------------------------------
                        s32Ret=HI_MPI_VENC_QueryStatus(i,&stStat);
                        if(HI_SUCCESS!=s32Ret)
                        {
                            LOGE("[MPP-VENC-ERROR]L_VENC_GetStream:HI_MPI_VENC_QueryStatus Chn[%d] failed with %#x!\n",i,s32Ret);
                            break;
                        }

                        //----------------------------------------
                        //因为监视到发生了读状态改变，所以使用select
                        //方法后这里的条件不应该发生。
                        //在不使用select、单独一个通道进行轮询的时候，
                        //可以通过此语句进行条件判断。
                        //----------------------------------------
                        if(0==stStat.u32CurPacks)
                        {
                            LOGD("[MPP-VENC-DEBUG]L_VENC_GetStream:Current frame is NULL!\n");
                            continue;
                        }

                        //----------------------------------------
                        //根据码流包的数量申请内存用于存放码流
                        //----------------------------------------
                        stStream.pstPack=(VENC_PACK_S*)malloc(sizeof(VENC_PACK_S)*stStat.u32CurPacks);
                        if(NULL==stStream.pstPack)
                        {
                            LOGE("[MPP-VENC-ERROR]L_VENC_GetStream:malloc stream pack failed!\n");
                            break;
                        }

                        //----------------------------------------
                        //而后就可以拿着这个结构体去领取码流
                        //----------------------------------------
                        stStream.u32PackCount=stStat.u32CurPacks;
                        s32Ret=HI_MPI_VENC_GetStream(i,&stStream,HI_TRUE);
                        if(HI_SUCCESS!=s32Ret)
                        {
                            free(stStream.pstPack);
                            stStream.pstPack=NULL;
                            LOGE("[MPP-VENC-ERROR]L_VENC_GetStream:HI_MPI_VENC_GetStream failed with %#x!\n",s32Ret);
                            break;
                        }

                        //----------------------------------------
                        //————————————码流处理说明————————————
                        //对码流获取完成之后，此处进行处理。
                        //
                        //在多包模式下，H264的I帧分为SPS、PPS、SEI、
                        //Islice四个NAL包。H265的I帧分为VPS、SPS、PPS、
                        //SEI、Islice五个NAL包。
                        //
                        //当仅图像编码时，由于抓拍不是实时的，所以
                        //启用DEBUG宏会出现Get VENC stream timeout.
                        //的提示，这是正常的。因为select循环必然超时。
                        //
                        //[注意]需要注意的是，在这个查询的循环里，
                        //变量i不仅用于循环，还代表了当前处理的通道号。
                        //因此在本段进行码流处理时应避免使用i变量作为
                        //循环变量或临时变量，以免发生错误或误操作。
                        //----------------------------------------
                        {
                            pStreamFuction(i,&stStream);//将当前通道的码流结构体地址传给处理函数
#ifdef SAVE_STREAM_TO_FILE
                            if(EnabledVencChn[i]==1)//当此包为视频流时
                            {
                                HI_S32 packagelength;
                                HI_U8 *stream;
                                HI_S32 j;
                                for(j=0;j<stStream.u32PackCount;j++)
                                {
                                    stream=stStream.pstPack[j].pu8Addr+stStream.pstPack[j].u32Offset;
                                    packagelength=stStream.pstPack[j].u32Len-stStream.pstPack[j].u32Offset;
                                    fwrite(stream,packagelength,1,pFile[i]);
                                    fflush(pFile[i]);
                                }
                            }
#endif
                        }

                        //----------------------------------------
                        //码流处理完成后应及时释放，以免造成编码暂停
                        //----------------------------------------
                        HI_MPI_VENC_ReleaseStream(i,&stStream);
                        free(stStream.pstPack);
                        stStream.pstPack=NULL;
                    }
                }
            }
        }
    }
#ifdef SAVE_STREAM_TO_FILE
    for(i=0;i<VENC_MAX_CHN_NUM;i++)
    {
        if(EnabledVencChn[i])
        {
            if(pFile[i])
            {
                fclose(pFile[i]);
            }
        }
    }
#endif
}
